#include "assert.h" 
#include "../../include/MathUtil/Vector.h"
#include <cmath>
#include <iostream>

using namespace z_vector;

Vector4f::Vector4f() :x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}

Vector4f::Vector4f(float x, float y, float z, float w) :x(x), y(y), z(z), w(w) {}

Vector4f::Vector4f(const Vector4f& vec) : x(vec.x), y(vec.y), z(vec.z), w(vec.w) {}

Vector4f::Vector4f(const Vector3f& vec, float w) : x(vec.x), y(vec.y), z(vec.z), w(w) {}

Vector4f::~Vector4f() {}

Vector4f Vector4f::operator+(const Vector4f& vec)
{
	return Vector4f(this->x + vec.x, this->y + vec.y, this->z + vec.z, this->w + vec.w);
}

Vector4f Vector4f::operator-(const Vector4f& vec)
{
	return Vector4f(this->x - vec.x, this->y - vec.y, this->z - vec.z, this->w - vec.w);
}

Vector4f Vector4f::operator*(const Vector4f& vec)
{
	return Vector4f(this->x * vec.x, this->y * vec.y, this->z * vec.z, this->w * vec.w);
}

Vector4f Vector4f::operator/(const Vector4f& vec)
{
	assert(vec.x != 0.0 && vec.y != 0.0 && vec.z != 0.0 && vec.w != 0.0);
	return Vector4f(this->x / vec.x, this->y / vec.y, this->z / vec.z, this->w / vec.w);
}

Vector4f Vector4f::operator*(float k)
{
	return Vector4f(this->x * k, this->y * k, this->z * k, this->w * k);
}

Vector4f Vector4f::operator/(float k)
{
	assert(k != 0);
	return Vector4f(this->x / k, this->y / k, this->z / k, this->w / k);
}

Vector4f Vector4f::operator+()
{
	return *this;
}

Vector4f Vector4f::operator-()
{
	return Vector4f(-this->x, -this->y, -this->z, -this->w);
}

float Vector4f::Dot(const Vector4f& v2)
{
	Vector4f& v1 = *this;
	return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
}

float z_vector::Vector4f::Magnitude()
{
	return sqrt(this->x * this->x + this->y * this->y + this->z * this->z + this->w * this->w);
}

Vector4f z_vector::Vector4f::Normalize()
{
	float length = Magnitude();
	if (length != 0.0f) {
		return Vector4f(*this / length);
	}
	return Vector4f(0.0f, 0.0f, 0.0f, 0.0f);
}


float Vector4f::Dot(const Vector4f& v1, const Vector4f& v2)
{
	return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
}

void Vector4f::printVec() {
	std::cout << "(x:" << x << " y:" << y << " z:" << z << " w:" << w << ")" << std::endl;
}

Vector4f Vector4f::lerp(Vector4f v2, double weight) {
	return Vector4f(
		this->x * (1.0 - weight) + weight * v2.x,
		this->y * (1.0 - weight) + weight * v2.y,
		this->z * (1.0 - weight) + weight * v2.z,
		this->w * (1.0 - weight) + weight * v2.w
	);
}
